﻿namespace Devonline.Core;

/// <summary>
/// key 生成器的参数构造器
/// key 的组成参照 SnowFlake 算法, 64 = 1 + 41 + 14? + 8?
/// 41 位毫秒值可以表示时间范围大约 69 年, 剩余 22 位为序列号和机器码
/// BenchmarkMachineCode    : 0xFF
/// MachineCode             : 0x00
/// </summary>
public class SnowFlakeOptions
{
    /// <summary>
    /// 初始化默认值
    /// </summary>
    public SnowFlakeOptions()
    {
        DataCenterCode = 0x00;
        MachineCode = 0x00;
    }

    /// <summary>
    /// 当前机器码, 最大 5 位二进制;
    /// 默认值 0x00; 即第 0 号机器节点;
    /// </summary>
    public int MachineCode { get; set; }
    /// <summary>
    /// 当前数据中心码, 最大 5 位二进制
    /// 默认值 0x00; 即第 0 号数据中心节点;
    /// </summary>
    public int DataCenterCode { get; set; }
}

/// <summary>
/// 借助 SnowFlake 实现的从配置文件读取配置初始化主键生成器
/// </summary>
public class KeyGenerator
{
    /// <summary>
    /// SnowFlake 实例
    /// </summary>
    private static readonly SnowFlake snowFlake;
    /// <summary>
    /// 读取的配置节点名称
    /// </summary>
    private const string SECTION_NAME = nameof(SnowFlake);
    /// <summary>
    /// 生成器参数
    /// </summary>
    private static readonly SnowFlakeOptions options = new();

    /// <summary>
    /// 计算配置生成器的值
    /// </summary>
    static KeyGenerator()
    {
        Configure();
        snowFlake = new SnowFlake(options.MachineCode, options.DataCenterCode);
    }
    /// <summary>
    /// 使用依赖注入方式在项目启动时注入生成器所需的参数值;
    /// 常规委托注入方式, 配置后不要修改;
    /// </summary>
    /// <param name="action">生成器的参数构造器委托</param>
    public static void Configure(Action<SnowFlakeOptions>? action = null)
    {
        action?.Invoke(options);
        if (options.MachineCode <= 0)
        {
            options.MachineCode = 0x00;
        }

        if (options.MachineCode >= 0x1F)
        {
            options.MachineCode = 0x1F;
        }

        if (options.DataCenterCode <= 0)
        {
            options.DataCenterCode = 0x00;
        }

        if (options.DataCenterCode >= 0x1F)
        {
            options.DataCenterCode = 0x1F;
        }
    }
    /// <summary>
    /// 获取最新的 key
    /// </summary>
    /// <returns></returns>
    public static long GetKey() => snowFlake.GetId();
    /// <summary>
    /// 获取对应类型的 key
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public static TKey GetKey<TKey>() where TKey : IConvertible => (TKey)Convert.ChangeType(snowFlake.GetId(), typeof(TKey));
}